package fr.cephb.joperon.tool.spindle;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.sleepycat.db.DatabaseException;

import fr.cephb.joperon.tool.OperonFactory;
import fr.cephb.joperon.core.Fid;
import fr.cephb.joperon.core.bio.Assembly;
import fr.cephb.joperon.core.bio.Chromosome;
import fr.cephb.joperon.core.db.GtypesDB;
import fr.cephb.joperon.core.db.SnpMapDB;
import fr.cephb.joperon.core.entities.Gtypes;
import fr.cephb.joperon.core.entities.MPanel;
import fr.cephb.joperon.core.entities.PrjDna;
import fr.cephb.joperon.core.entities.PrjFin;
import fr.cephb.joperon.core.entities.SnpMap;

public class Spindle
	{
	private Assembly assembly= Assembly.getDefaultAssembly();
	private Chromosome chromosome= null;
	private int start=0;
	private int end=0;
	private OperonFactory factory;
	private PrjFin selectedPrjFin;
	private PrjDna prjdna;

	
	public void setAssembly(Assembly assembly) {
		this.assembly = assembly;
		}
	
	

	
	public Chromosome getChromosome() {
		return chromosome;
		}
	
	public void setChromosome(String s)
		{
		if(s==null) throw new IllegalArgumentException("Bad chromosome "+s);
		Chromosome c= Chromosome.getByName(s);
		if(c==null) throw new IllegalArgumentException("Bad chromosome "+s);
		this.chromosome = c;
		}
	
	public Assembly getAssembly() {
		return assembly;
	}
	
	public int getStart() {
		return start;
	}
	
	public int getEnd() {
		return end;
	}
	
	public void setStart(int start)
		{
		start=Math.max(0, start);
		start=Math.min(start, Fid.MAX_VALUE);
		this.start = start;
		}
	
	public void setEnd(int end)
		{
		end=Math.max(0, end);
		end=Math.min(end, Fid.MAX_VALUE);
		this.end = end;
		}
	
	public void setFactory(OperonFactory factory) {
		this.factory = factory;
		}
	
	public OperonFactory getFactory() {
		return factory;
		}
	
	
	
	public void setPrjFin(PrjFin selectedPrjFin) {
		this.selectedPrjFin = selectedPrjFin;
		}
	
	public PrjFin getPrjFin() {
		return selectedPrjFin;
		}
	
	public void setPrjDna(PrjDna prjdna) {
		this.prjdna = prjdna;
		}
	
	public PrjDna getPrjDna() {
		return prjdna;
		}
	
	
	public void preprocess() throws DatabaseException
		{
		}
	
	public void printByColumn(PrintWriter out) throws DatabaseException
		{
		SnpMapDB.ValueIterator iter=null;
		GtypesDB gdb=null;
		PrjDna.Individual individuals[]=getPrjDna().getIndividuals();
		try {
			gdb= new GtypesDB(factory.getOperon(),getAssembly(),getPrjDna().getAcn());
			if(! gdb.exists() )
				{
				out.println("#not gtypes for "+gdb.getName()+" "+getPrjDna().getAcn());
				return;
				}
			gdb.open();
			/*out.println(
					"fid,chr,chrpos,marker,family,individual,father,mother,sex,status,batch,sample," +
					"genotype,ca,aa,score,panel,cv,flags".replace(',', '\t')
					);*/
			
			out.print(
					"marker,chr,position,ca,ra,aa,flags".replace(',', '\t')
					);
			
			for(int i=0;i< individuals.length;++i)
				{
				out.print("\t");
				out.print(individuals[i].getName());
				}
			out.println();
			
			iter= getFactory().getSnpMap(getAssembly()).listBetween(
					getChromosome(), getStart(), getEnd());
			while(iter.hasNext())
				{
				SnpMap map= iter.next();
				List<Gtypes> genotypes = gdb.getConcatenedValues(map.getFid());
				if(genotypes==null || genotypes.isEmpty()) continue;
				
				out.print(map.getAcn()); out.print("\t");
				out.print(map.getChromosome()); out.print("\t");
				out.print(map.getPosition()); out.print("\t");
				out.print(map.getCa()); out.print("\t");
				out.print(map.getRa()); out.print("\t");
				out.print(map.getAa()); 
				
				for(int i=0;i< individuals.length;++i)
					{
					out.print("\t");
					out.print(genotypes.get(i).getAlleles());
					}
					
					
				out.println();
				}
			}
		catch (Exception e)
			{
			e.printStackTrace(out);
			throw new DatabaseException(e);
			}
		finally
			{
			if(gdb!=null) gdb.close();
			if(iter!=null) iter.close();
			}
		out.flush();
		}
	
	
	public void printByRow(PrintWriter out) throws DatabaseException
		{
		SnpMapDB.ValueIterator iter=null;
		GtypesDB gdb=null;
		PrjDna.Individual individuals[]=getPrjDna().getIndividuals();
		try {
			gdb= new GtypesDB(factory.getOperon(),getAssembly(),getPrjDna().getAcn());
			if(! gdb.exists() )
				{
				out.println("#not gtypes for "+gdb.getName()+" "+getPrjDna().getAcn());
				return;
				}
			gdb.open();
			out.println(
					("fid,chr,chrpos,marker,family,individual,father,mother,sex,status,batch,sample," +
					"genotype,ca,aa,score,panel,cv,flags").replace(',', '\t')
					);
			
			
			
			iter= getFactory().getSnpMap(getAssembly()).listBetween(
					getChromosome(), getStart(), getEnd());
			while(iter.hasNext())
				{
				SnpMap map= iter.next();
				List<Gtypes> genotypes = gdb.getConcatenedValues(map.getFid());
				if(genotypes==null || genotypes.isEmpty()) continue;
				
				
				for(int i=0;i< individuals.length;++i)
					{
					PrjDna.Individual indi=individuals[i];
					
					out.print(map.getFid().asString()); out.print("\t");
					out.print(map.getChromosome()); out.print("\t");
					out.print(map.getPosition()); out.print("\t");
					out.print(map.getAcn()); out.print("\t");
					
					out.print(indi.getFamilyId()); out.print("\t");
					out.print(indi.getIndividualId()); out.print("\t");
					out.print(indi.getFatherId()); out.print("\t");
					out.print(indi.getMotherId()); out.print("\t");
					out.print(indi.getSex()); out.print("\t");
					out.print(indi.getStatus()); out.print("\t");
					out.print(indi.getBatch()); out.print("\t");
					out.print(indi.getName()); out.print("\t");
					
					
					out.print(genotypes.get(i).getAlleles()); out.print("\t");
					
					out.print(map.getCa()); out.print("\t");
					out.print(map.getAa()); out.print("\t");
					out.print(-1.00); out.print("\t");
					out.print(prjdna.getAcn()); out.print("\t");
					out.print(map.getCv());  out.print("\t");
					out.print(map.getFlags()); 
					
					out.println();
					
					
					}
				}
			}
		catch (Exception e)
			{
			e.printStackTrace(out);
			throw new DatabaseException(e);
			}
		finally
			{
			if(gdb!=null) gdb.close();
			if(iter!=null) iter.close();
			}
		out.flush();
		}
	
	}
